#pragma once

#include <string>
#include <vector>
#include <functional>
#include <mutex>
#include <atomic>
#include <thread>
#include <chrono>
#include <queue>
#include <iomanip>

#include <stdint.h>
#include <glog/logging.h>
#include "agile_modbus.h"

#ifndef _CONFIG_H_
#define MAX_ADU_LENGTH AGILE_MODBUS_MAX_ADU_LENGTH
#endif



class agile_modbus_rtu_master_simple
{
private:
   uint8_t ctx_send_buf[MAX_ADU_LENGTH];
   uint8_t ctx_read_buf[MAX_ADU_LENGTH];
   uint32_t ctx_max_buf_len;

   std::string name;
   agile_modbus_rtu_t ctx_rtu;
   agile_modbus_t *ctx;
   std::mutex ctx_mutex;

   std::function<int(uint8_t* data)> recv_callback;
   std::function<int(uint8_t* data,uint32_t send_size)> send_callback;

   int init_flag;

   enum read_write_type
   {
      COILS,
      DISCRETE_INPUTS,
      INPUT_REGISTERS,
      HOLDING_REGISTERS
   };

   int _read_slave(read_write_type type, uint8_t slave_id, uint16_t addr, uint32_t num,std::vector<uint16_t> &data,bool is_force_muti = false);
   int _write_slave(read_write_type type, uint8_t slave_id, uint16_t addr, uint32_t num, std::vector<uint16_t> &data,bool is_force_muti = false);
public:
   
   agile_modbus_rtu_master_simple(std::string &name_,
                                  std::function<int(uint8_t* data,uint32_t send_size)> send_callback_,
                                  std::function<int(uint8_t* data)> recv_callback_);

   ~agile_modbus_rtu_master_simple();

   int init();

   int read_coil_single(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);
   int read_discrete_input_single(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);
   int read_input_register_single(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);
   int read_holding_register_single(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);

   int write_coil_single(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);
   int write_holding_register_single(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);

   int read_coil_multiple(uint8_t slave_id, uint16_t addr,  std::vector<uint16_t> &data);
   int read_discrete_input_multiple(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);
   int read_holding_register_multiple(uint8_t slave_id, uint16_t addr,  std::vector<uint16_t> &data);
   int read_input_register_multiple(uint8_t slave_id, uint16_t addr,  std::vector<uint16_t> &data);

   int write_coil_multiple(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);
   int write_holding_register_multiple(uint8_t slave_id, uint16_t addr, std::vector<uint16_t> &data);

   uint32_t read_max_buffer_size();
};
